---
title: 预获取
description: 预获取链接以在页面间实现更快的导航。
i18nReady: true
---

import { Steps } from '@astrojs/starlight/components'
import Since from '~/components/Since.astro'

页面加载时间在网站的可用性和整体体验中扮演着重要角色。当你的访问者与网站进行交互时，Astro 的**可选预获取**功能能在你的多页面应用（MPA）中带来几乎瞬时的页面导航的好处。

## 启用预获取

你可以使用 `prefetch` 配置来启用预获取：

```js title="astro.config.mjs" ins={4}
import { defineConfig } from 'astro/config';

export default defineConfig({
  prefetch: true
});
```

一个预获取脚本将被添加到你网站的所有页面。然后你可以在你网站的任何 `<a />` 链接上添加 `data-astro-prefetch` 属性来选择预获取。当你将鼠标悬停在链接上时，脚本将在后台获取页面。

```html
<a href="/about" data-astro-prefetch>
```

注意，预获取只适用于你的网站内的链接，不适用于外部链接。

## 预获取配置

`prefetch` 配置也接受一个选项对象，以进一步自定义预获取。

### 预获取策略

Astro 支持 4 种预获取策略，以适应各种用例：

- `hover`（默认）：当你将鼠标悬停在链接上或聚焦在链接上时预获取。
- `tap`：在你点击链接之前预获取。
- `viewport`：当链接进入视口时预获取。
- `load`：当页面加载后预获取当前页面的所有链接。

你可以通过将其传递给 `data-astro-prefetch` 属性来为单个链接指定策略：

```html
<a href="/about" data-astro-prefetch="tap">About</a>
```

每种策略都经过了微调，只有在需要时才预获取，以节省用户的带宽。例如：

- 如果访问者使用[流量节省模式](https://developer.mozilla.org/zh-CN/docs/Web/API/NetworkInformation/saveData)或者有[慢速连接](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType)，则预获取策略将会回退到 “tap” 策略。
- 快速悬停或滚动链接不会预获取它们。

### 默认预获取策略

添加 `data-astro-prefetch` 属性时的默认预获取策略是 `hover`。要更改它，你可以在你的 `astro.config.mjs` 文件中配置 [`prefetch.defaultStrategy`](/zh-cn/reference/configuration-reference/#prefetchdefaultstrategy)：

```js title="astro.config.mjs" ins={4-6}
import { defineConfig } from 'astro/config';

export default defineConfig({
  prefetch: {
    defaultStrategy: 'viewport'
  }
});
```

### 默认预获取所有链接

如果你想预获取所有链接，包括那些没有 `data-astro-prefetch` 属性的链接，你可以将 [`prefetch.prefetchAll`](/zh-cn/reference/configuration-reference/#prefetchprefetchall) 设置为 `true`：

```js title="astro.config.mjs" ins={4-6}
import { defineConfig } from 'astro/config';

export default defineConfig({
  prefetch: {
    prefetchAll: true
  }
});
```

然后你可以通过设置 `data-astro-prefetch="false"` 来为单个链接选择不进行预获取：

```html
<a href="/about" data-astro-prefetch="false">About</a>
```

所有链接的默认预获取策略可以通过 `prefetch.defaultStrategy` 更改，如 [默认预获取策略部分](#默认预获取策略) 所示。

## 可编程的预获取

由于一些导航可能不总是以 `<a />` 链接的形式出现，你也可以使用 `astro:prefetch` 模块中的 `prefetch()` API 进行程序化预获取：

```astro
<button id="btn">Click me</button>

<script>
  import { prefetch } from 'astro:prefetch';

  const btn = document.getElementById('btn');
  btn.addEventListener('click', () => {
    prefetch('/about');
  });
</script>
```

`prefetch()` API 包括相同的[流量节省模式](https://developer.mozilla.org/zh-CN/docs/Web/API/NetworkInformation/saveData)和[慢速连接](https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType)检测，因此只有在需要时才预获取。

要忽略慢速连接检测，你可以使用 `ignoreSlowConnection` 选项：

```js
// 即使在数据保护模式或慢速连接下也能预获取
prefetch('/about', { ignoreSlowConnection: true });
```

### `eagerness`

<p>
**类型：** `'immediate' | 'eager' | 'moderate' | 'conservative'`<br />
**默认值：** `'immediate'`<br />
<Since v="5.6.0" />
</p>

当启用实验性的 [`clientPrerender`](/zh-cn/reference/experimental-flags/client-prerender/) 标志时，你可以使用 `prefetch()` 上的 `eagerness` 选项，向浏览器建议应以何种积极程度去预获取/预渲染目标链接。

该选项参照 [推测规则 API](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/speculationrules#eagerness) 中相同的 API 描述，并默认为 `immediate`（最积极的选项）。将积极程度降序排列，依次为 `eager`、`moderate` 和 `conservative`。

`eagerness` 选项允许你在减少用户等待时间的优势与带宽、内存及 CPU 开销之间进行权衡。部分浏览器（如 Chrome）设置了 [针对过度推测的防护性限制](https://developer.chrome.com/blog/speculation-rules-improvements?hl=zh-cn#chrome-limits)，（以防止预渲染/预获取过多的链接）。

 ```astro
---
---
<script>
// 使用 `experimental.clientPrerender` 以控制预获取的积极程度
import { prefetch } from 'astro:prefetch';

// 该页面为资源密集型
prefetch('/data-heavy-dashboard', { eagerness: 'conservative' });

// 该页面关乎用户的浏览体验
prefetch('/getting-started'); // 默认为 `{ eagerness: 'immediate' }`

// 该页面可能并不会被访问
prefetch('/terms-of-service', { eagerness: 'moderate' });
</script>
```

要对大量的链接使用程序化的 `prefetch()`，你可以设置为 `eagerness: 'moderate'`，从而利用 [先进先出算法（FIFO）](https://zh.wikipedia.org/wiki/先進先出演算法) 和启发式算法，来让浏览器自行决定，以何种顺序、以及在何时去预渲染/预获取这些链接。

```astro "{eagerness: 'moderate'}"
<a class="link-moderate" href="/nice-link-1">A Nice Link 1</a>
<a class="link-moderate" href="/nice-link-2">A Nice Link 2</a>
<a class="link-moderate" href="/nice-link-3">A Nice Link 3</a>
<a class="link-moderate" href="/nice-link-4">A Nice Link 4</a>
...
<a class="link-moderate" href="/nice-link-20">A Nice Link 20</a>

<script>
  import { prefetch } from 'astro:prefetch';
  const linkModerate = document.getElementsByClassName('link-moderate');
  linkModerate.forEach((link) => prefetch(link.getAttribute('href'), {eagerness: 'moderate'}));
  
</script>
```

确保只在客户端脚本中导入 `prefetch()`，因为它依赖于浏览器 API。

## 与视图过渡动画一起使用

当你在页面上使用 [Astro 的 `<ClientRouter />`](/zh-cn/guides/view-transitions/#启用视图过渡动画spa-模式) 时，预获取也将默认启用。它设置了一个默认配置 `{ prefetchAll: true }`，在页面上启用 [所有链接的预获取](#默认预获取所有链接)。

你可以在 `astro.config.mjs` 中自定义预获取配置以覆盖默认设置。例如：
  
```js title="astro.config.mjs"
import { defineConfig } from 'astro/config';

export default defineConfig({
  // 完全禁用预获取
  prefetch: false
});
```

```js title="astro.config.mjs"
import { defineConfig } from 'astro/config';

export default defineConfig({
  // 保留预获取，但只对带有 `data-astro-prefetch` 的链接进行预获取
  prefetch: {
    prefetchAll: false
  }
});
```

## 浏览器支持

如果浏览器支持，Astro 的预获取将使用 [`<link rel="prefetch">`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Attributes/rel/prefetch)，否则将回退到 [`fetch()` API](https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API)。

常见的浏览器对 Astro 的预获取支持存在细微差别：

### Chrome

Chrome 支持 `<link rel="prefetch">`。预获取按预期工作。

同时它也全面支持来自 [推测规则 API](https://developer.mozilla.org/zh-CN/docs/Web/API/Speculation_Rules_API) 的 `<script type="speculationrules">`，此 API 可用于进一步定义 [预获取策略和规则](#eagerness)，从而为 Chrome 用户优化体验。若需在 `prefetch()` 中启用此功能，你需要先启用 [`clientPrerender`](/zh-cn/reference/experimental-flags/client-prerender/) 实验性标志。

### Firefox

Firefox 支持 `<link rel="prefetch">`，但可能会显示错误或完全失败：

- 如果没有明确的缓存头（例如 [`Cache-Control`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control) 或 [`Expires`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Expires)），预获取将会因 `NS_BINDING_ABORTED` 错误而失败。
- 即使出现错误，如果响应中有正确的 [`ETag`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/ETag) 头，它将在导航时被重用。
- 否则，如果没有其他缓存头的错误，预获取将不会工作。

### Safari

Safari 不支持 `<link rel="prefetch">`，将回退到 `fetch()` API，这需要设置缓存头（例如 [`Cache-Control`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control)、[`Expires`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Expires) 和 [`ETag`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/ETag)）。否则，预获取将不会工作。

**特殊情况：** 在隐私窗口中，`ETag` 头不起作用。

### 建议

为了更好地支持所有浏览器，请确保你的页面设置了正确的缓存头。

对于静态或预渲染的页面，`ETag` 头通常由部署平台自动设置，并且预期可以直接使用。

对于动态和服务端渲染的页面，根据页面内容自行设置适当的缓存头。更多信息请访问 [MDN 关于 HTTP 缓存的文档](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching)。

## 从 `@astrojs/prefetch` 迁移

`@astrojs/prefetch` 集成在 v3.5.0 中被弃用，最终将被完全移除。使用以下说明将 `@astrojs/prefetch` 迁移到 Astro 的内置预获取，这将替代这个集成。

<Steps>
1. 删除 `@astrojs/prefetch` 集成，并在 `astro.config.mjs` 中启用 `prefetch` 配置：

    ```js title="astro.config.mjs" ins={6} del={2,5}
    import { defineConfig } from 'astro/config';
    import prefetch from '@astrojs/prefetch';

    export default defineConfig({
      integrations: [prefetch()],
      prefetch: true
    });
    ```

2. 从 `@astrojs/prefetch` 的配置选项转换：

    - 已弃用的集成使用 `selector` 配置选项来指定哪些链接应在进入视口时被预获取。
    
      而现在，你需要在这些单独的链接上添加 `data-astro-prefetch="viewport"`。

      ```html
      <a href="/about" data-astro-prefetch="viewport">
      ```

    - 已弃用的集成使用 `intentSelector` 配置选项来指定哪些链接在被悬停或聚焦时应被预获取。
    
      现在，你需要在这些单独的链接上添加 `data-astro-prefetch` 或 `data-astro-prefetch="hover"`：

      ```html
      <!-- 如果 `defaultStrategy` 设置为 `hover`（默认），你可以省略值 -->
      <a href="/about" data-astro-prefetch>

      <!-- 否则，你可以明确定义预获取策略 -->
      <a href="/about" data-astro-prefetch="hover">
      ```

    - `@astrojs/prefetch` 的 `throttles` 选项不再需要，因为新的预获取特性将自动调度和优化预获取。
</Steps>
